package com.jie.service.impl;

import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.jie.constant.IMTerminalType;
import com.jie.constant.MessageStatus;
import com.jie.dto.FriendDTO;
import com.jie.dto.OperationLogDTO;
import com.jie.dto.PrivateMessageDTO;
import com.jie.dto.UserDetailDTO;
import com.jie.exception.BusinessException;
import com.jie.mapper.FriendImMapper;
import com.jie.netty.clinet.IMClient;
import com.jie.netty.model.IMPrivateMessage;
import com.jie.netty.model.IMUserInfo;
import com.jie.pojo.SingleChat;
import com.jie.mapper.SingleChatMapper;
import com.jie.service.FriendImService;
import com.jie.service.SingleChatService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.jie.util.BeanCopyUtils;
import com.jie.util.BeanUtils;
import com.jie.util.UserUtils;
import com.jie.vo.ConditionVO;
import com.jie.vo.PageResult;
import com.jie.vo.SingleChatMessageVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import java.time.LocalDateTime;
import java.time.temporal.ChronoUnit;
import java.util.Collections;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;

import static com.jie.constant.CommonConst.FALSE;
import static com.jie.enums.BizCodeEnum.FRIEND_ERROR;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author xiaojie
 * @since 2023-11-01
 */
@Slf4j
@Service
public class SingleChatServiceImpl extends ServiceImpl<SingleChatMapper, SingleChat> implements SingleChatService {
    @Autowired
    private FriendImMapper friendImMapper;
    @Autowired
    private IMClient imClient;
    @Autowired
    private FriendImService friendImService;
    @Override
    public Long sendMessage(SingleChatMessageVO vo) {
        Long userInfoId = UserUtils.getLoginUser().getUserInfoId();
        //1.判断和对方是否为好友关系 TODO 高并发接口需要将查询数据库的操作都进行缓存
        if (!ObjectUtil.isAllNotEmpty(friendImMapper.isFriend(userInfoId,vo.getRecvId()))){
            throw new BusinessException(FRIEND_ERROR.getCode(),FRIEND_ERROR.getMessage());
        }
        //2.将信息进行保存
        // 保存消息
        SingleChat msg = SingleChat.builder()
                .senderId(userInfoId)
                .receiverId(vo.getRecvId())
                .context(vo.getContent())
                .contextType(vo.getType())
                .isDelete(FALSE)
                .state(MessageStatus.UN_SEND.code())
                .build();
        this.save(msg);
        //将消息转换为私人消息格式进行推送
        IMPrivateMessage<Object> sendMessage = IMPrivateMessage.builder()
                .messageId(msg.getId())
                .sender(new IMUserInfo(userInfoId,UserUtils.getLoginUser().getTerminal()))
                .recvId(msg.getReceiverId())
                .data(vo.getContent())
                .recvTerminals(IMTerminalType.codes())
                .sendToSelf(true)
                .sendResult(true)
                .build();
        //推送至mq进行消费
        imClient.sendPrivateMessage(sendMessage);
        //4.返回这条信息的id
        return msg.getId();
    }

    /**
     * 拉取已读消息
     * @param minId 消息起始id
     * @return 聊天消息列表
     */
    @Override
    public List<PrivateMessageDTO> loadMessage(Long minId) {
        //获取当前对象
        UserDetailDTO user = UserUtils.getLoginUser();
        //根据当前对象获取全部好友
        List<FriendDTO> friends = friendImService.findFriendByUserId(user.getUsername());
        if (friends.isEmpty()) {
            return Collections.EMPTY_LIST;
        }
        //获取全部好友的信息id
        List<Long> friendIds = friends.stream().map(FriendDTO::getReceiverId).collect(Collectors.toList());
        // 获取当前用户的消息
        //拉取最近一个月的消息列表
        LocalDateTime minDate = LocalDateTimeUtil.offset(user.getLastLoginTime(), -31, ChronoUnit.DAYS);
        List<SingleChat> messages = this.baseMapper.selectList(new LambdaQueryWrapper<SingleChat>()
                .ge(SingleChat::getId, minId)
                .ge(SingleChat::getCreateTime, minDate)
                .ne(SingleChat::getState, MessageStatus.RECALL.code())
                .and(wrap -> wrap.and(
                                wp -> wp.eq(SingleChat::getSenderId, user.getUserInfoId())
                                        .in(SingleChat::getReceiverId, friendIds))
                        .or(wp -> wp.eq(SingleChat::getReceiverId, user.getUserInfoId())
                                .in(SingleChat::getSenderId, friendIds)))
                .orderByAsc(SingleChat::getId)
                .last("limit 100"));
        // 更新发送状态
        List<Long> ids = messages.stream()
                .filter(m -> !m.getSenderId().equals(user.getUserInfoId()) && m.getState().equals(MessageStatus.UN_SEND.code()))
                .map(SingleChat::getId)
                .collect(Collectors.toList());
        if (!ids.isEmpty()) {
            this.update(new LambdaUpdateWrapper<SingleChat>().in(SingleChat::getId,ids)
                    .set(SingleChat::getState, MessageStatus.SENDED.code()));
        }
        log.info("拉取消息，用户id:{},数量:{}", user.getUserInfoId(), messages.size());
        return messages.stream().map(m -> BeanUtils.copyProperties(m, PrivateMessageDTO.class)).collect(Collectors.toList());
    }

    @Override
    public void readMessage(Long friendId) {
        //获取当前对象
        UserDetailDTO user = UserUtils.getLoginUser();
        // 修改消息状态为已读
        this.update(new LambdaUpdateWrapper<SingleChat>()
                .eq(SingleChat::getSenderId, friendId)
                .eq(SingleChat::getReceiverId, user.getUserInfoId())
                .eq(SingleChat::getState, MessageStatus.SENDED.code())
                .set(SingleChat::getUpdateTime,LocalDateTimeUtil.now())
                .set(SingleChat::getState, MessageStatus.READED.code()));
        log.info("消息已读，接收方id:{},发送方id:{}", user.getUserInfoId(), friendId);
    }

    /**
     * 根据好友id查询历史记录
     * @param friendId
     * @param conditionVO
     * @return
     */
    @Override
    public PageResult<PrivateMessageDTO> findHistoryMessage(Long friendId, ConditionVO conditionVO) {
        Page<SingleChat> page = new Page<>(conditionVO.getCurrent(), conditionVO.getSize());
        Long userId = UserUtils.getLoginUser().getUserInfoId();
        // 查询日志列表
        Page<SingleChat> singleChatPage = this.page(page, new LambdaQueryWrapper<SingleChat>()
                .and(wrap -> wrap.and(
                                wp -> wp.eq(SingleChat::getSenderId, userId)
                                        .eq(SingleChat::getReceiverId, friendId))
                        .or(wp -> wp.eq(SingleChat::getReceiverId, userId)
                                .eq(SingleChat::getSenderId, friendId)))
                .ne(SingleChat::getState, MessageStatus.RECALL.code())
                .orderByDesc(SingleChat::getId));
        List<PrivateMessageDTO> operationLogDTOList = BeanCopyUtils.copyList(singleChatPage.getRecords(), PrivateMessageDTO.class);
        log.info("消息历史查询，接收方id:{},发送方id:{},查询数目:{}", UserUtils.getLoginUser().getUserInfoId(), friendId,(int) singleChatPage.getTotal());
        return new PageResult<>(operationLogDTOList, (int) singleChatPage.getTotal());

    }


}
